import re
import time
import paramiko

from logger.logger import Log
from core import utils
from core.auto_test import AutoTest
import api.config
from core.serial_port import SerialPort


class Connect:
    def start(self):
        # ssh连接
        if self.is_ssh_con:
            # 加载系统中已知的主机公钥到 SSHClient 对象中，这样在 SSH 连接时就可以自动进行主机密钥的验证，确保连接的安全性。
            self.ssh.load_system_host_keys()
            # 在连接到未知主机时自动添加其主机密钥到本地 Known Hosts 文件中的策略
            self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.ssh.connect(self.connect_ip, port=self.connect_port, username=self.connect_user,
                             password=self.connect_pwd)
            self.is_connect = True
            c = api.config.Config(self)
            # 创建一个交互式的 shell 通道，可以在远程服务器上执行命令并与其进行交互
            self.invoke = self.ssh.invoke_shell()
            # exepath = "/root"  cd root
            self.invoke.send(("cd " + self.exepath + '\n').encode())
            time.sleep(1)
            while True:
                # 检查远程 shell 通道是否有数据可以接收。如果远程服务器向 shell 通道发送了数据，此方法将返回 True
                if self.invoke.recv_ready():
                    try:
                        # 获取远程服务器返回的数据
                        self.data = self.invoke.recv(5000).decode('utf-8')
                        # print(self.data)
                    except Exception as e:
                        Log.logger.error(e)
                        Log.logger.error("utf-8")
                        try:
                            self.data = self.invoke.recv(5000).decode('gbk')
                        except Exception as e1:
                            Log.logger.error(e1)
                            try:
                                self.data = self.invoke.recv(5000).decode('ISO-8859-1')
                            except Exception as e2:
                                Log.logger.error(e2)
                                try:
                                    self.data = self.invoke.recv(5000).decode('latin-1')
                                except Exception as e3:
                                    Log.logger.error(e3)
                                    self.data = self.invoke.recv(5000).decode('utf-8', errors='ignore')

                    # pid_kill = FALSE
                    if not self.pid_kill:
                        # if:如果有进程则杀掉进程，如果没有就创建一个新的线程
                        # 匹配前面是换行符（\r 或 \n）的数字序列,返回一个子集列表
                        # 杀掉已有的zigbee_bridage进程
                        if len(re.findall('(?<=\r|\n)\d+', self.data)) > 0:
                            self.pid = re.findall('(?<=\r|\n)\d+', self.data)[0]
                            Log.logger.info('pid is {}'.format(self.pid))
                            self.invoke.send(("kill -9  {}".format(self.pid) + '\n').encode())
                            output = self.invoke.send(("kill -9  {}".format(self.pid) + '\n').encode())
                            if output == 14:
                                Log.logger.info('pid {} has been killed'.format(self.pid))
                            else:
                                Log.logger.info('pid {} has not been killed,please check!'.format(self.pid))
                            time.sleep(3)

                        # send  ./zigbee_bridge
                        self.invoke.send(("./" + self.exe + '\n').encode())
                        time.sleep(1)
                        self.pid_kill = True
                        self.pid = 1
                        # 创建一个新线程 config.start()
                        utils.run_with_thread(c.start)
                    # pid_kill = TRUE
                    else:
                        if AutoTest.running:
                            # 加上远程服务器返回的数据
                            AutoTest.temp_data += self.data
                else:
                    continue
                # 数据中有以['TestCase']['endstr']为结尾  "#"
                if self.data.endswith(self.end_str+"  ") or self.data.endswith(self.end_str+" "):
                    # pid_kill = TRUE pid = NONE
                    if self.pid_kill and self.pid is None:
                        # 根据进程的名称或其他属性来查找和列出匹配的进程ID
                        self.invoke.send(("pgrep " + self.exe + '\n').encode())
                        time.sleep(2)
                        self.pid_kill = False
        # 不是ssh连接
        else:
            #   ['Gateway']['SerialPort'] = COM3  ['Gateway']['SerialBitrate'] = 115200
            self.serial = SerialPort(self.serial_port, self.serial_bitrate)
            try:
                # 串口对象被成功创建并打开，并且获取了当前可读取的字节数
                self.serial.open()
            except Exception as e:
                Log.logger.error("网关串口打开失败，请检查接线与配置文件！！！")
            if self.serial.is_open():
                Log.logger.info("Open Gateway Serial Successful")
                self.is_connect = True
                # 串口是否登录
                while not self.login_by_serial:
                    self.serial_login()
                c = api.config.Config(self)
                # exepath = "/root"  cd root
                self.send_msg("cd " + self.exepath + '\n')
                while True:
                    # read_serial_data = TRUE
                    # ssh的send_msg方法置TRUE
                    if self.read_serial_data:
                        self.read_serial_data = False
                        # 尝试从串口中读取数据，在等待一段时间后检查是否有可读取的数据，并根据情况读取不同长度的数据进行返回
                        self.data = self.serial.read(1000).decode('utf-8')
                        Log.logger.info(self.data)
                        # pid_kill = FALSE
                        if not self.pid_kill:
                            # if:如果有进程则杀掉进程，如果没有就创建一个新的线程
                            # 匹配前面是换行符（\r 或 \n）的数字序列,返回一个子集列表
                            # 杀掉已有的zigbee_bridage进程
                            self.pid = re.findall('(?<=\r)\d+', self.data)[0]
                            if len(self.pid) > 0:
                                Log.logger.info('pid is {}'.format(self.pid))
                                self.send_msg(("kill -9  {}".format(self.pid) + '\n'))
                                time.sleep(3)
                            # send  ./zigbee_bridge
                            self.send_msg("./" + self.exe + '\n')
                            self.pid_kill = True
                            self.pid = 1
                            # 创建一个新进程
                            utils.run_with_thread(c.start)
                        else:
                            if AutoTest.running:
                                # 加上远程服务器返回的数据
                                AutoTest.temp_data += self.data

                    else:
                        continue
                    # 根据进程的名称或其他属性来查找和列出匹配的进程ID
                    if self.data.endswith(self.end_str+"  ") or self.data.endswith(self.end_str+" "):
                        if self.pid_kill and self.pid is None:
                            self.send_msg("pgrep " + self.exe + '\n')
                            self.pid_kill = False

    # 用于串口登录
    def serial_login(self):
        # 根据输入的数据类型(输入是否包含 HEX )，进行不同的处理方式，最终将处理后的数据写入到串口中
        self.serial.write('\n')
        self.data = self.serial.read(1000).decode('utf-8')
        print(self.data)
        # 串口登录的账号密码输入
        if "OpenWrt login:" in self.data:
            self.serial.write('root\n')
            self.data = self.serial.read(1000).decode('utf-8')
            print(self.data)
            if "Password:" in self.data:
                self.serial.write('admin\n')
                self.data = self.serial.read(1000).decode('utf-8')
                print(self.data)
        # 串口登录网关成功
        elif 'root@OpenWrt:' in self.data:
            self.login_by_serial = True
            Log.logger.info("串口登录网关成功\r\n")
        else:
            self.serial.write('\n')
            self.data = self.serial.read(1000).decode('utf-8')

    def send_msg(self, msg):
        msg = msg.replace('\r', '').replace('\n', '')
        # 找到第一个左花括号{之前的部分
        head = re.findall('.+(?={)', msg)[0]
        # 找到第一个左花括号{和右花括号}之间的部分
        body = re.findall('{.*}', msg)[0]
        msg = head + body.replace(' ', '')
        # 检查连接
        if self.is_connect:
            if self.is_ssh_con:
                self.invoke.send((msg + '\n').encode())
                log = "[Send Gateway Msg ]: {}".format(msg.encode())
                Log.logger.info(log)
                time.sleep(1)
            else:
                self.serial.write(msg + '\n')
                log = "[Send Gateway Msg ]: {}".format(msg.encode())
                Log.logger.info(log)
                self.read_serial_data = True

    def close(self):
        if self.is_ssh_con:
            self.ssh.close()
        else:
            self.serial.close()

    def __init__(self):
        self.is_connect = False
        self.pid = None
        self.pid_kill = True
        self.data = str()
        self.serial = None
        self.invoke = None
        self.end_str = api.config.Config.arg['TestCase']['endstr']
        self.exepath = api.config.Config.arg['TestCase']['exepath']
        self.exe = api.config.Config.arg['TestCase']['exe']
        self.is_ssh_con = True if api.config.Config.arg['Gateway']['Connect'] == 'SSH' else False
        if self.is_ssh_con:
            self.ssh = paramiko.SSHClient()
            self.connect_ip = api.config.Config.arg['Gateway']['IPAddress']
            self.connect_user = api.config.Config.arg['Gateway']['Username']
            self.connect_pwd = api.config.Config.arg['Gateway']['Password']
            self.connect_port = api.config.Config.arg['Gateway']['Port']
        else:
            self.login_by_serial = False
            self.read_serial_data = False
            # 串行端口的名称或者设备文件名
            self.serial_port = api.config.Config.arg['Gateway']['SerialPort']
            # 波特率
            self.serial_bitrate = int(api.config.Config.arg['Gateway']['SerialBitrate'])
